import { log } from './log.ts'

type valueType = null | undefined | 'string' | 'array' | 'object' | 'number' | false
export function variableType(value: any): valueType {
  if (value === null) return null
  if (value === undefined) return undefined
  if (typeof value === 'number') return 'number'
  if (typeof value === 'string') return 'string'
  if (Array.isArray(value)) return 'array'
  if (isObject(value)) return 'object'
  return false
}
// Determine whether a variable is of type object and not array
export function isObject(value: any): boolean {
  return typeof value === 'object' && !Array.isArray(value)
}

/**
 * Merge two arrays and remove duplicates. Only applicable to basic types.
 * Not a base type, simply merging two arrays won't deduplicate
 */
type baseType = string | boolean | number | symbol
export function mergeArr(
  origin: (baseType | any)[],
  target: (baseType | any)[],
): boolean | (baseType | any)[] {
  if (!Array.isArray(origin) || !Array.isArray(target)) {
    log.error('Please enter the correct type')
    return false
  }
  const _target = new Set(target)
  for (let i = 0; i < origin.length; ++i) {
    const item = origin[i]!!
    if (_target.has(item)) continue
    _target.add(item)
  }
  return Array.from(_target)
}

function objectTree(origin: any, target: any): boolean | any {
  const originKeys = Object.keys(origin)
  const _target = target
  for (let i = 0; i < originKeys.length; ++i) {
    const key = originKeys[i]!!
    const value = origin[key]
    if (Object.hasOwn(target, key)) {
      const type = variableType(value)
      if (!type) {
        log.error(`Merge key: ${key} error. Because the value type is ${type}`)
        continue
      }
      const _value = target[key]
      if (type !== variableType(_value)) {
        log.warn(
          `The key: ${key} value is different. The value type is ${type}. The target value type is ${variableType(_value)}`,
        )
        continue
      }
      if (type === 'array') {
        _target[key] = mergeArr(value, _value)
        // console.log('array', _target[key])
      } else if (type === 'object') {
        _target[key] = objectTree(value, _value)
      }
    } else {
      _target[key] = value
    }
  }
  return _target
}

/**
 * merge object
 * such as : a ={ test: { t: a, c: [] }} b = { test: { t: b }} -> b = { test: { t: b, c: []}}
 * @param {Object} origin
 * @param {Object} target
 * @returns target | false
 */
export function mergeObject(origin: any, target: any) {
  if (!isObject(origin) || !isObject(target)) return false
  return objectTree(origin, target)
}
